﻿using JWT;
using log4net;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UserService.Entity;

namespace jczUserService.Handlers
{
    public class JwtAuthenticationMessageHandler : DelegatingHandler
    {
        private const string BearerScheme = "Bearer";
       // private const string SecretKey = "9fdb64ec22e9cda94ad9964d07dd9dd16ee8c41a8e0d4367e1d09d2520ae583cb8357a992edb76a74a4b866243580b6106f6497733641f588f8608f391443138";
        private Log _logtx=new Log();
        //private readonly ILog _logger = _logtx.CLog;

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)
        {
            var authHeader = request.Headers.Authorization;
            if (authHeader == null)
            {
                _logtx.CLog.Info("Missing authorization header");
                return base.SendAsync(request, cancellationToken);
            }

            if (authHeader.Scheme != BearerScheme)
            {
                _logtx.CLog.InfoFormat(
                    "Authorization header scheme is {0}; needs to {1} to be handled as a JWT.",
                    authHeader.Scheme,
                    BearerScheme);
                return base.SendAsync(request, cancellationToken);
            }

            var tokenString = authHeader.Parameter;

            try
            {
                var user = GetUserFromJWT(tokenString);
                //var principal = new ClaimsPrincipal(user.ToClaimsIdentity());

                //request.GetRequestContext().Principal = principal;

                //_logtx.CLog.DebugFormat("Thread principal set with identity '{0}'", principal.Identity.Name);
            }
            catch (SignatureVerificationException signatureEx)
            {
                _logtx.CLog.WarnFormat("Invalid JWT token found in Authorization header of request.");
            }
            catch (Exception e)
            {
                _logtx.CLog.ErrorFormat("Error during JWT validation: {0}", e);
                throw;
            }

            return base.SendAsync(request, cancellationToken);
        }

        public static string CreateJWT(jczClaims user)
        {
            string _RootPath = AppDomain.CurrentDomain.GetData(".appPath").ToString();
            ExeConfigurationFileMap map = new ExeConfigurationFileMap();
            map.ExeConfigFilename = _RootPath + @"\bin\jczUserService.dll.config";
            Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
            string SecretKey = config.AppSettings.Settings["SecretKey"].Value;
            string RandomKey = config.AppSettings.Settings["RandomKey"].Value;
            return JsonWebToken.Encode(user, SecretKey, JwtHashAlgorithm.HS512, RandomKey);
        }

        public static jczClaims GetUserFromJWT(string jwt)
        {
            string _RootPath = AppDomain.CurrentDomain.GetData(".appPath").ToString();
            ExeConfigurationFileMap map = new ExeConfigurationFileMap();
            map.ExeConfigFilename = _RootPath + @"\bin\jczUserService.dll.config";
            Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
            string SecretKey = config.AppSettings.Settings["SecretKey"].Value;
            string RandomKey = config.AppSettings.Settings["RandomKey"].Value;
            var jsonPayload = JsonWebToken.Decode(jwt, SecretKey, RandomKey);
            return JsonConvert.DeserializeObject<jczClaims>(jsonPayload);
        }

        ///<summary>
        ///生成随机字符串 
        ///</summary>
        ///<param name="length">目标字符串的长度</param>
        ///<param name="useNum">是否包含数字，1=包含，默认为包含</param>
        ///<param name="useLow">是否包含小写字母，1=包含，默认为包含</param>
        ///<param name="useUpp">是否包含大写字母，1=包含，默认为包含</param>
        ///<param name="useSpe">是否包含特殊字符，1=包含，默认为不包含</param>
        ///<param name="custom">要包含的自定义字符，直接输入要包含的字符列表</param>
        ///<returns>指定长度的随机字符串</returns>
        public static string GetRandomString(int length, bool useNum, bool useLow, bool useUpp, bool useSpe, string custom)
        {
            byte[] b = new byte[4];
            new System.Security.Cryptography.RNGCryptoServiceProvider().GetBytes(b);
            Random r = new Random(BitConverter.ToInt32(b, 0));
            string s = null, str = custom;
            if (useNum == true) { str += "0123456789"; }
            if (useLow == true) { str += "abcdefghijklmnopqrstuvwxyz"; }
            if (useUpp == true) { str += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; }
            if (useSpe == true) { str += "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; }
            for (int i = 0; i < length; i++)
            {
                s += str.Substring(r.Next(0, str.Length - 1), 1);
            }
            return s;
        }
    }
}
